package org.etnaframework.module.redis;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.time.Duration;
import java.time.temporal.ChronoUnit;

/**
 * jedis连接配置辅助类，目前仅适用于redis单机版
 *
 * @author jasyaf
 * @since 2023-11-15
 */
public class RedisTemplateFactory implements InitializingBean {

    protected final Logger log = LoggerFactory.getLogger(getClass());

    private final RedisTemplateFactoryConfig config;

    public RedisTemplateFactory(RedisTemplateFactoryConfig config) {
        this.config = config;
    }

    private RedisTemplate[] redisTemplates;

    private RedisConnectionFactory[] redisConnectionFactories;

    /**
     * 初始化redis连接，使用实例下所有的库
     */
    @Override
    public void afterPropertiesSet() throws Exception {

        long start = System.currentTimeMillis();

        GenericObjectPoolConfig<Jedis> poolConfig = new GenericObjectPoolConfig<>();
        poolConfig.setMaxTotal(config.getPoolMaxTotal());
        poolConfig.setMaxIdle(config.getPoolMaxIdle());

        redisTemplates = new RedisTemplate[config.getTotalDbNum()];
        redisConnectionFactories = new RedisConnectionFactory[config.getTotalDbNum()];

        for (int i = 0; i < redisTemplates.length; i++) {
            redisTemplates[i] = new RedisTemplate(new JedisPool(poolConfig, config.getHost(), config.getPort(), config.getTimeoutMs(), config.getPassword(), i, config.getUseSsl()));

            RedisStandaloneConfiguration standaloneConfiguration = new RedisStandaloneConfiguration(config.getHost(), config.getPort());
            standaloneConfiguration.setPassword(config.getPassword());
            standaloneConfiguration.setDatabase(i);

            JedisClientConfiguration.JedisClientConfigurationBuilder clientConfig = JedisClientConfiguration.builder();
            clientConfig.connectTimeout(Duration.of(config.getTimeoutMs(), ChronoUnit.MILLIS));
            clientConfig.readTimeout(Duration.of(config.getTimeoutMs(), ChronoUnit.MILLIS));
            clientConfig.usePooling().poolConfig(poolConfig);
            if (config.getUseSsl()) {
                clientConfig.useSsl();
            }

            JedisConnectionFactory factory = new JedisConnectionFactory(standaloneConfiguration, clientConfig.build());
            factory.afterPropertiesSet();
            redisConnectionFactories[i] = factory;
        }

        // 检查连接可用性，如果有问题会抛异常
        try (RedisConnection connection = redisConnectionFactories[0].getConnection()) {
            connection.time();
        }
        redisTemplates[0].server().time();
        log.info("{} for [{}:{}] initialized in {}ms", getClass().getSimpleName(), config.getHost(), config.getPort(), System.currentTimeMillis() - start);
    }

    /**
     * 获取下标对应库的{@link RedisTemplate}，不检查下标，请调用方自行确保不会越界
     */
    public RedisTemplate db(int index) {
        return redisTemplates[index];
    }

    /**
     * 获取下标对应库的{@link RedisConnectionFactory}，不检查下标，请调用方自行确保不会越界
     */
    public RedisConnectionFactory dbFactory(int index) {
        return redisConnectionFactories[index];
    }
}
